package com.alibaba.algo.domain.user;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.algo.cooperation.common.BaseResult;
import com.alibaba.algo.cooperation.feign.vo.req.SelectAppResourceReqVO;
import com.alibaba.algo.cooperation.feign.vo.req.SelectRoleResourceActionReqVO;
import com.alibaba.algo.cooperation.feign.vo.req.SelectRoleResourceReqVO;
import com.alibaba.algo.cooperation.feign.vo.req.SelectUserResourceReqVO;
import com.alibaba.algo.cooperation.feign.vo.res.ResourceActionResVO;
import com.alibaba.algo.cooperation.feign.vo.res.ResourceResVO;
import com.alibaba.algo.cooperation.feign.vo.res.RoleResourceActionResVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.ActionData;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.ResourceActionRequestVO;
import com.alibaba.algo.cooperation.usercomponent.vo.req.user.SelectResourceListRequestVO;
import com.alibaba.algo.core.base.Pager;
import com.alibaba.algo.core.base.PagerEntity;
import com.alibaba.algo.core.exception.BaseException;
import com.alibaba.algo.dao.user.SysActionMapper;
import com.alibaba.algo.dao.user.SysResourceActionMapper;
import com.alibaba.algo.dao.user.SysResourceMapper;
import com.alibaba.algo.entity.user.SysAction;
import com.alibaba.algo.entity.user.SysResource;
import com.alibaba.algo.entity.user.SysResourceAction;
import com.alibaba.algo.enums.EnvType;
import com.alibaba.algo.enums.SysResourceTypeEnum;
import com.alibaba.algo.exception.BaseErrorCode;
import com.alibaba.algo.util.DateConverterUtils;
import com.alibaba.algo.utils.UserContextUtils;
import com.xxl.sso.core.user.XxlSsoUser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类SysResource.java的实现描述：资源Domain
 *
 * @author nieganggang 2021-03-12 16:08:17
 */
@Component
public class SysResourceDomain {

    @Resource
    private SysResourceMapper sysResourceMapper;

    @Resource
    private SysActionMapper sysActionMapper;

    @Resource
    private SysResourceActionMapper sysResourceActionMapper;

    @Value("${env.type}")
    private String env;

    private final List<Long> ids = new ArrayList<>();

    /**
     * 查询资源列表,菜单资源下的角色列表
     *
     * @param selectResourceListRequestVO 入参
     * @return 结果
     */
    public PagerEntity<SysResource> selectResourcePage(SelectResourceListRequestVO selectResourceListRequestVO) {
        if (ObjectUtils.isEmpty(selectResourceListRequestVO.getPageIndex())) {
            throw new BaseException(BaseErrorCode.PAGE_INDEX_IS_NULL.getCode(), BaseErrorCode.PAGE_INDEX_IS_NULL.getMessage());
        }
        if (ObjectUtils.isEmpty(selectResourceListRequestVO.getPageSize())) {
            throw new BaseException(BaseErrorCode.PAGE_SIZE_IS_NULL.getCode(), BaseErrorCode.PAGE_SIZE_IS_NULL.getMessage());
        }
        if (StringUtils.isEmpty(selectResourceListRequestVO.getAppCode())) {
            throw new BaseException(BaseErrorCode.APP_CODE_IS_NULL.getCode(), BaseErrorCode.APP_CODE_IS_NULL.getMessage());
        }
        //菜单根目录赋值
        if (ObjectUtils.isEmpty(selectResourceListRequestVO.getParentId())) {
            SysResource sysResource = sysResourceMapper.qryResourceRoot(selectResourceListRequestVO.getAppCode());
            selectResourceListRequestVO.setParentId(sysResource.getId());
        } else {
            List<Long> ids = qryChildrenResource(selectResourceListRequestVO.getParentId(), selectResourceListRequestVO.getAppCode());
            ids.add(selectResourceListRequestVO.getParentId());
            selectResourceListRequestVO.setResourceIds(ids);
            selectResourceListRequestVO.setParentId(null);
        }

        Integer total = sysResourceMapper.selectResourcePageCount(selectResourceListRequestVO);
        Pager pager = Pager.newInstance(total.longValue(), selectResourceListRequestVO.getPageIndex(), selectResourceListRequestVO.getPageSize());
        List<SysResource> result = sysResourceMapper
                .selectResourcePage(selectResourceListRequestVO, pager.getStart(), pager.getEnd());
        return new PagerEntity<>(total, pager.getTotalPages(), pager.getPageSize(), pager.getPageIndex(), result);
    }

    private List<Long> qryChildrenResource(Long resourceId, String appCode) {
        List<SysResource> resources = sysResourceMapper.getChildResourceListByParentId(appCode, resourceId);
        if (!CollectionUtils.isEmpty(resources)) {
            resources.forEach(item -> {
                ids.add(item.getId());
                qryChildrenResource(item.getId(), appCode);
            });
        }
        return ids;
    }

    @Transactional(rollbackFor = Exception.class)
    public BaseResult updateResourceAction(ResourceActionRequestVO param) {
        ActionData actionData = param.getActionData();
        Long actionId = actionData.getActionId();
        XxlSsoUser currentUser = UserContextUtils.getCurrentUser();
        assert currentUser != null;
        SysAction sysAction = generateSysAction(actionData, param.getAppCode(), currentUser);
        SysResourceAction sysResourceAction = generateSysResourceAction(actionData, param.getAppCode(), param.getResourceId(), currentUser);
        SysAction action = sysActionMapper.selectByCodeAndApp(actionData.getActionCode(), param.getAppCode());
        if (actionId > -1) {
            if (!actionId.equals(action.getId())) {
                return BaseResult.buildError("按钮编码已存在，请重新设置！");
            }
            sysActionMapper.updateById(sysAction);
            sysResourceActionMapper.updateById(sysResourceAction);
        } else {
            if (!ObjectUtils.isEmpty(action) && "N".equals(action.getIsDeleted())) {
                return BaseResult.buildError("按钮编码已存在，请重新设置！");
            } else if (!ObjectUtils.isEmpty(action) && "Y".equals(action.getIsDeleted())) {
                //存在且已删除则恢复
                sysAction.setId(action.getId());
                sysActionMapper.validAction(sysAction);
                sysResourceActionMapper.validResourceAction(sysResourceAction);
            } else if (ObjectUtils.isEmpty(action)) {
                if (!EnvType.DEV.getValue().equals(env)) {
                    return BaseResult.buildError("uat和pro环境不支持新增功能！");
                }
                //不存在则新增
                sysActionMapper.insert(sysAction);
                action = sysActionMapper.selectByCodeAndApp(actionData.getActionCode(), param.getAppCode());
                sysResourceAction.setActionId(action.getId());
                sysResourceActionMapper.insert(sysResourceAction);
            }
        }
        return BaseResult.buildSuccess("更新成功！");
    }

    private SysAction generateSysAction(ActionData actionData, String appCode, XxlSsoUser currentUser) {
        SysAction sysAction = new SysAction();
        BeanUtil.copyProperties(actionData, sysAction);
        sysAction.setId(actionData.getActionId());
        sysAction.setAppCode(appCode);
        LocalDateTime cutDateTime = DateConverterUtils.asLocalDateTime(new Date());
        sysAction.setModifier(currentUser.getUserid());
        sysAction.setGmtModified(cutDateTime);
        if (actionData.getActionId() < 0) {
            sysAction.setId(null);
            sysAction.setCreator(currentUser.getUserid());
            sysAction.setGmtCreated(cutDateTime);
        }
        return sysAction;
    }

    private SysResourceAction generateSysResourceAction(ActionData actionData, String appCode, Long resourceId, XxlSsoUser currentUser) {
        SysResourceAction sysResourceAction = new SysResourceAction();
        BeanUtil.copyProperties(actionData, sysResourceAction);
        sysResourceAction.setId(actionData.getResourceActionId());
        sysResourceAction.setResourceId(resourceId);
        sysResourceAction.setAppCode(appCode);
        sysResourceAction.setSort(actionData.getSort());
        LocalDateTime cutDateTime = DateConverterUtils.asLocalDateTime(new Date());
        sysResourceAction.setModifier(currentUser.getUserid());
        sysResourceAction.setGmtModified(cutDateTime);
        if (actionData.getResourceActionId() < 0) {
            sysResourceAction.setId(null);
            sysResourceAction.setCreator(currentUser.getUserid());
            sysResourceAction.setGmtCreated(cutDateTime);
        }

        return sysResourceAction;
    }

    public void removeResourceAction(ResourceActionRequestVO param) {
        ActionData actionData = param.getActionData();
        sysActionMapper.deleteById(actionData.getActionId());
        sysResourceActionMapper.deleteById(actionData.getResourceActionId());
    }

    public void removeResource(Long resourceId) {
        sysResourceMapper.deleteById(resourceId);
        List<SysResourceAction> sysResourceActions = sysResourceActionMapper.selectByResourceId(resourceId);
        if (!CollectionUtils.isEmpty(sysResourceActions)) {
            sysResourceActions.forEach(sysResourceAction -> {
                sysResourceActionMapper.deleteById(sysResourceAction.getId());
                sysActionMapper.deleteById(sysResourceAction.getActionId());
            });
        }
    }

    public void insertResourceAction(SysResourceAction sysResourceAction) {
        sysResourceActionMapper.insert(sysResourceAction);
    }

    public void updateResourceAction(SysResourceAction sysResourceAction) {
        sysResourceActionMapper.updateById(sysResourceAction);
    }

    public void insertAction(SysAction sysAction) {
        sysActionMapper.insert(sysAction);
    }

    public void updateAction(SysAction sysAction) {
        sysActionMapper.updateById(sysAction);
    }

    /**
     * 查询用户指定类型的资源列表
     *
     * @param
     * @return 用户标识
     */
    public List<Long> selectResourceIdListByUserId(SelectUserResourceReqVO vo, List<Integer> resourceTypeList) {
        return sysResourceMapper.selectResourceIdListByUserId(vo, resourceTypeList);
    }

    /**
     * 查询菜单资源列表,下级菜单向拥有父级菜单的权限
     *
     * @param
     * @return 菜单资源列表
     */
    public List<Long> selectMenuResourceIdList(SelectUserResourceReqVO vo) {
        // 查询用户所拥有的资源列表
        List<Long> resourceIdList = this.selectResourceIdListByUserId(vo, Collections.singletonList(SysResourceTypeEnum.MENU.getValue()));
        if (CollectionUtils.isEmpty(resourceIdList)) {
            return Collections.emptyList();
        }
        return resourceIdList.stream().distinct().collect(Collectors.toList());
    }

    public List<SysResource> selectResourceIdListRecursiveToRoot(Long id) {
        return sysResourceMapper.selectResourceIdListRecursiveToRoot(id);
    }

    public List<ResourceResVO> qryResourceListByRoleId(SelectRoleResourceReqVO vo) {
        return sysResourceMapper.qryResourceListByRoleId(vo);
    }

    public List<RoleResourceActionResVO> qryRoleResourceActionListByRoleId(SelectRoleResourceActionReqVO vo) {
        return sysResourceMapper.qryRoleResourceActionListByRoleId(vo);
    }

    public List<ResourceResVO> qryResourceListByAppOrPath(SelectAppResourceReqVO vo) {
        return sysResourceMapper.qryResourceListByAppOrPath(vo);
    }

    public List<ResourceActionResVO> qryResourceActionListByAppOrPath(SelectAppResourceReqVO vo) {
        return sysResourceMapper.qryResourceActionListByAppOrPath(vo);
    }

    /*
        查询菜单下的按钮详情
     */
    public List<ResourceActionResVO> qryResourceActionByIdAndAppCode(Long resourceId, String appCode) {
        return sysResourceMapper.qryResourceActionByIdAndAppCode(resourceId, appCode);
    }

    public List<SysResourceAction> qryByResourceIdAndAppCode(Long resourceId, String appCode) {
        return sysResourceMapper.qryByResourceIdAndAppCode(resourceId, appCode);
    }

    public SysResourceAction qryByResourceActionId(Long resourceActionId) {
        return sysResourceMapper.qryByResourceActionId(resourceActionId);
    }

    public List<SysResource> qryResourcesByIds(List<Long> ids) {
        return sysResourceMapper.qryResourceByIds(ids);
    }

    public SysAction getActionById(Long id) {
        return sysActionMapper.getById(id);
    }

    public SysResource getById(Long id) {
        return sysResourceMapper.getById(id);
    }

    public void updateById(SysResource sysResource) {
        sysResourceMapper.updateById(sysResource);
    }

    public void insert(SysResource sysResource) {
        sysResourceMapper.insert(sysResource);
    }

    public SysResource qryResourceRoot(String appCode) {
        return sysResourceMapper.qryResourceRoot(appCode);
    }

    public List<SysResource> getChildResourceListByParentId(String appCode, Long resourceId) {
        return sysResourceMapper.getChildResourceListByParentId(appCode, resourceId);
    }

    public List<ResourceResVO> getChildResourceListByParentIdForSub(String appCode, List<Long> roleIds, Long resourceId) {
        return sysResourceMapper.getChildResourceListByParentIdForSub(appCode, roleIds, resourceId);
    }

    public SysResource qryResourceByResourceCodeAndAppCode(String resourceCode, String appCode) {
        return sysResourceMapper.qryResourceByResourceCodeAndAppCode(resourceCode, appCode);
    }

    public Long qryResourceRootId(String appCode) {
        return sysResourceMapper.qryResourceRootId(appCode);
    }

    public List<SysResourceAction> qryResourceAction(String appCode, Long resourceId, List<Long> roleIds) {
        return sysResourceActionMapper.qryResourceAction(appCode, resourceId, roleIds);
    }
}
